#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "StdThreadPool.h"
#include "StdThread.h"
#include "LinkQueue.h"
#include "DoubleLinkList.h"


struct StdThreadPool
{
    DLlist threads;//线程链表 
    LQueue* taskQueue;//任务队列
    int MaxThreadNumber;//最大线程数
    int MinThreadNumber;//最小线程数
    int MaxQueueSize;//最大任务队列

    int BusyThreadNum;//忙碌线程数:有多少线程正在工作
    Mutex *BsyThrdMtx;//忙碌线程锁,专门控制上面的变量
    int minusNum;//需要被退出的线程数量

    Mutex *poolMutex;//线程池的锁
    Cond *queueNotEmpty;//队列不为空的条件变量
    Cond *queueNotFull;//队列不为满的条件变量

    Thread *manager;//管理者线程
    int sleepTime;//管理者线程的检查周期

    bool shutDown;//关闭线程池标志
};

typedef struct 
{
    void* (*funcPtr)(void*);
    void *arg;
}Task;

Task* CreateTask(void* (*funcPtr)(void *),void *arg)
{
    Task* t = (Task*)malloc(sizeof(Task));
    if(t == NULL)
        return NULL;

    t->funcPtr = funcPtr;
    t->arg = arg;
    return t;
}

void FreeTask(void *t)
{
    Task *task = (Task*)t;
    free(task);
}

bool IsThreadEqual(void *ptr1,void *ptr2)
{
    Thread *t = (Thread*)ptr1;
    unsigned long int ID = (unsigned long int)ptr2;
    if(GetThreadId(t) == ID)
        return true;
    return false;
}

void *ThreadHandler(void *arg)
{
    ThreadP *p = (ThreadP*)arg;
    while(1)
    {
        //阻塞：没有任务
        MutexLock(p->poolMutex);
        while(IsQueueEmpty(p->taskQueue) == true && p->shutDown == false)
        {
            CondWait(p->queueNotEmpty,p->poolMutex);

            //自杀线程
            MutexLock(p->BsyThrdMtx);
            if(p->minusNum == 0)
            {
                MutexUnlock(p->BsyThrdMtx);
            }
            else
            {
                RemoveByElement(&p->threads,(void*)GetSelfThrdID(),IsThreadEqual,ClearThread);
                p->minusNum--;
                MutexUnlock(p->BsyThrdMtx);
                MutexUnlock(p->poolMutex);
                //线程退出
                return NULL;
            }
        }
        
        //线程池准备退出，线程退出
        if(p->shutDown == true)
        {
            MutexUnlock(p->poolMutex);
            return NULL;
        }

        //有任务唤醒，从任务队列中将任务取出
        //GetQFront取的是值的指针的指针
        Task *t = (Task*)*GetQFront(p->taskQueue);
        QPop(p->taskQueue);
        //有任务被取出，可以向任务队列中加任务
        CondBroadcast(p->queueNotFull);
        MutexUnlock(p->poolMutex);

        //准备忙任务
        MutexLock(p->BsyThrdMtx);
        p->BusyThreadNum++;
        MutexUnlock(p->BsyThrdMtx);

        //做任务  
        t->funcPtr(t->arg);
        FreeTask(t);

        //线程闲下来了，没有工作要处理
        MutexLock(p->BsyThrdMtx);
        p->BusyThreadNum--;
        MutexUnlock(p->BsyThrdMtx);
    }
    

    
}

void *ThreadManager(void *arg)
{
    ThreadP *p = (ThreadP*)arg;
    while(p->shutDown == false)
    {
        sleep(p->sleepTime);
        MutexLock(p->poolMutex);

        //1、加线程的情况：任务数量等于线程数量
        if(GetQueueLen(p->taskQueue) > p->threads.len && p->threads.len < p->MaxThreadNumber)
        {
            //加线程的标准并不是唯一的
            int MaxAddNum = p->MaxThreadNumber - p->threads.len;//能加的最大数量
            int shouldAddNum = GetQueueLen(p->taskQueue) / 2;//理论上应该加的数量
            int addNum = MaxAddNum > shouldAddNum ? shouldAddNum : MaxAddNum;
            for(int i = 0; i < addNum; i++)
                InsertDLlistTail(&p->threads,InitThread(ThreadHandler,p));
            
        }
        //2、减线程的情况：有一半的线程都不在工作
        MutexLock(p->BsyThrdMtx);
        if(p->BusyThreadNum * 2 < p->threads.len && p->threads.len > p->MinThreadNumber)
        {
            int MaxMinusNum = p->threads.len - p->MinThreadNumber;//能减去的最大的线程数量
            int shouldMinusNum = (p->threads.len - p->BusyThreadNum) / 2;//应该要减去的线程数量
            int minusNum = MaxMinusNum > shouldMinusNum ? shouldMinusNum : MaxMinusNum;
            for(int i = 0 ; i < minusNum; i++)
                CondSignal(p->queueNotEmpty);
        }
        MutexUnlock(p->BsyThrdMtx);

        MutexUnlock(p->poolMutex);
    }
}

ThreadP *InitThreadPool(int MaxThreadNumber,int MinThreadNumber,int MaxQueueSize,int second)
{
    ThreadP *p = (ThreadP*)malloc(sizeof(ThreadP));
    if(p == NULL)
        return NULL;

    //初始化
    InitDLlist(&p->threads);
    p->taskQueue = InitLQueue();

    p->MaxThreadNumber = MaxThreadNumber;
    p->MinThreadNumber = MinThreadNumber;
    p->MaxQueueSize = MaxQueueSize;
    p->sleepTime = second;
    p->minusNum = 0;

    p->BusyThreadNum = 0;
    p->BsyThrdMtx = InitMutex();

    p->poolMutex = InitMutex();
    p->queueNotEmpty = InitCond();
    p->queueNotFull = InitCond();

    //初始化开辟线程
    for(int i = 0; i < p->MaxThreadNumber; i++)
    {
        InsertDLlistTail(&p->threads,InitThread(ThreadHandler,p));
    }

    //创建管理者线程
    p->manager = InitThread(ThreadManager,p);
    p->shutDown = false;
    return p;
}

void AddPoolTask(ThreadP *p, void *(*funcPtr)(void *), void *arg)
{
    MutexLock(p->poolMutex);
    //任务队列为满时
    while(GetQueueLen(p->taskQueue) == p->MaxQueueSize && p->shutDown == false)
    {
        //等待队列不满的条件
        CondWait(p->queueNotEmpty,p->poolMutex);
    }

    //线程池准备退出，线程退出
    if(p->shutDown == true)
    {
        MutexUnlock(p->poolMutex);
        return;
    }

    //添加任务
    QPush(p->taskQueue,CreateTask(funcPtr,arg));
    //唤醒线程
    CondBroadcast(p->queueNotEmpty);

    MutexUnlock(p->poolMutex);
}


void thrdJoinCallback(void *ptr)
{
    Thread *t = (Thread*)ptr;
    //线程回收
    ThreadJoin(t);
}
void ClearThreadPool(ThreadP *p)
{
    if(p == NULL)
        return;
    p->shutDown = true;

    //先回收管理者线程
    ThreadJoin(p->manager);
    free(p->manager);

    //先唤醒正在睡觉的线程
    for(int i = 0; i < p->threads.len; i++)
    {
        CondSignal(p->queueNotEmpty);
    }

    //依次等待线程回收
    TravelDLlist(&p->threads,thrdJoinCallback);

    //线程链表清空,链表指向的内存清空
    ClearDLlist(&p->threads,ClearThread);

    //清空任务队列
    ClearLQueue(p->taskQueue,FreeTask);

    //清空锁
    ClearMutex(p->poolMutex);
    ClearMutex(p->BsyThrdMtx);

    //清空条件变量
    ClearCond(p->queueNotEmpty);
    ClearCond(p->queueNotFull);

    //最后清空自己
    free(p);
}
